struct position {
	int x, y;
};
typedef struct position Position;

struct task_node {
    int id;
	int height, width;
	int arrival_time;
	int execution_time;
	int deadline_time;
	Position *pos;
	E_Node *ienode, *oenode;
	struct task_node *next, *prev;
};
typedef struct task_node Task_Node;

struct task_list {
	Task_Node *head, *tail;	
};
typedef struct task_list Task_List;

void print_t(Task_Node *current) {
    			printf("M%02d w:%d, h:%d, a:%d, e:%d\n",
    			current->id,
				current->width,
				current->height,
				current->arrival_time,
				current->execution_time
			);
}

void print_task2(Task_List *list) {
	Task_Node *current = NULL;
	if (list == NULL) {
		printf("print_tasks2: Empty list\n");
	} else {
		printf("print_tasks2: List contains\n");
		current = list->head;

		while (current != NULL) {
            printf("print_tasks2: ");
			print_t(current);
			current = current->next;
		}
	}
}

void print_task(Task_List *list) {
	Task_Node *current = NULL;
	if (list == NULL) {
		printf("Empty list\n");
	} else {
		printf("List contains\n");
		current = list->head;

		while (current != NULL) {
			printf("w:%d, h:%d, a:%d, e:%d, x:%d, y:%d\n",
				current->width,
				current->height,
				current->arrival_time,
				current->deadline_time,
				current->pos->x,
				current->pos->y
			);
			current = current->next;
		}
	}
}

void read_task(Task_Node **task, FILE *fp) {
	int id, arrival_time, deadline_time, execution_time;
	int height, width;

	fscanf(fp, "%d %d %d %d %d %d\n", &id, &arrival_time, &execution_time, &deadline_time, &width, &height);
	(*task) = (Task_Node *) malloc(sizeof(Task_Node));
	(*task)->id = id;
	(*task)->height = height;
	(*task)->width = width;
	(*task)->arrival_time = arrival_time;
	(*task)->execution_time = execution_time;
	(*task)->deadline_time = deadline_time;
	(*task)->next = NULL;
	(*task)->prev = NULL;
	(*task)->pos = NULL;
//	printf("task w:%d, h:%d\n", (*task)->width, (*task)->height);
/*
	(*task)->pos = (Position *) malloc (sizeof (Position));
	(*task)->pos->x = arrival_time;
	(*task)->pos->y = deadline_time;
*/
}

void add_task(Task_List **tasks, Task_Node *newTask) {
	if ((*tasks) == NULL) {
		(*tasks) = (Task_List *) malloc (sizeof (Task_List));
		newTask->next = NULL;
		newTask->prev = NULL;
		(*tasks)->head = newTask;
		(*tasks)->tail = newTask;
	} else {
		newTask->prev = (*tasks)->tail;
		newTask->next = NULL;
		(*tasks)->tail->next = newTask;
		(*tasks)->tail = newTask;
	}
}

void delete_task(Task_List **tasks, Task_Node *current, Task_Node *previous) {
//    Task_Node *delete_t = NULL;
/*     if ((*tasks) != NULL) {
//        print_task2(*tasks);
        delete_t = (*tasks)->head;
        if (delete_t->next == NULL) {
            free((*tasks));
            (*tasks) = NULL;
        } else {
            (*tasks)->head = delete_t->next;
            delete_t->next = NULL;
        }
//        print_task2(*tasks);
    } */
    if ((*tasks) == NULL) {
        printf("delete_task: List of task is empty\n");
        exit(-1);
    }
    if ((*tasks)->head == current) {
        if (current->next == NULL) {
            free((*tasks));
            (*tasks) = NULL;
        } else {
            (*tasks)->head = current->next;
            (*tasks)->head->prev = NULL;
        }
    } else {
        previous->next = current->next;
        if (current->next != NULL) {
            current->next->prev = previous;
        }
    }
        
        
/* 	if (current->prev == NULL) { // head
		(*tasks)->head = current->next;
		if (current->next == NULL) { // tail
			(*tasks) = NULL;
		} else {
			current->next->prev = NULL;
		}
	} else {
		if (current->next == NULL) {
			current->prev->next = NULL;
			(*tasks)->tail = current->prev;
		} else {
			current->prev->next = current->next;
			current->next->prev = current->prev;
		}
	} */
}

void reduce_time(Task_List **tasks, Task_List **removeTasks) {
	if ((*tasks) != NULL) {
		Task_Node *current = (*tasks)->head;
		Task_Node *previous = NULL;
		while (current != NULL) {
//            printf("reduce_time: exec_t:%2d ",current->execution_time);
//            print_t(current);
			current->execution_time--;
			if (current->execution_time == 0) {
				Task_Node *temp = current->next;
				delete_task(tasks, current, previous);
				add_task(removeTasks, current);
				current = temp;
			} else {
				previous = current;
				current = current->next;
			}
		}
	}
}

void t_insert_last(Task_List **list, Task_Node *newNode) {
	if ((*list) == NULL) {
		(*list) = (Task_List *) malloc (sizeof (Task_List));
		newNode->next = NULL;
		newNode->prev = NULL;
		(*list)->head = newNode;
		(*list)->tail = newNode;
	} else {
		newNode->prev = (*list)->tail;
		newNode->next = NULL;
		(*list)->tail->next = newNode;
		(*list)->tail = newNode;
	}
}

void insert_after(Task_List **list, Task_Node *newNode, Task_Node *currentNode) {
//    printf("insert_after\n");
    if (currentNode == NULL) {
        newNode->next = (*list)->head;
        (*list)->head = newNode;
    } else {
        newNode->next = currentNode->next;
        currentNode->next = newNode;
    }
}   

void schedule_FCFS(Task_List **list, Task_Node *newNode) {
    Task_Node *current = NULL, *insert_location = NULL;
//    printf("First Come First Serve\n");
    if ((*list) == NULL) {
        (*list) = (Task_List *) malloc (sizeof (Task_List));
        (*list)->head = newNode;
    } else {
        current = (*list)->head;
        insert_location = NULL;
        while (current != NULL) {
            if (current->arrival_time <= newNode->arrival_time) {
                insert_location = current;
            }
            current = current->next;
        }
        insert_after(list, newNode, insert_location);
    }
}

void schedule_SJF(Task_List **list, Task_Node *newNode) {
    Task_Node *current = NULL, *insert_location = NULL;
//    printf("Shortest Job First\n");
    if ((*list) == NULL) {
        (*list) = (Task_List *) malloc (sizeof (Task_List));
        (*list)->head = newNode;
    } else {
        current = (*list)->head;
        insert_location = NULL;
        while (current != NULL) {
            if ((current->execution_time <= newNode->execution_time) && (current->arrival_time <= newNode->arrival_time)) {
                insert_location = current;
            }
            current = current->next;
        }
        insert_after(list, newNode, insert_location);
    }
}


